package com.vhall.component.service.exam.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.vhall.component.dao.exam.ExamAnswersMapper;
import com.vhall.component.dao.exam.ExamMapper;
import com.vhall.component.dao.exam.ExamRoomLkMapper;
import com.vhall.component.entity.exam.ExamAnswerEntity;
import com.vhall.component.entity.exam.ExamEntity;
import com.vhall.component.entity.exam.vo.*;
import com.vhall.component.entity.page.vo.PageVO;
import com.vhall.component.entity.room.RoomExamLkEntity;
import com.vhall.component.entity.room.dto.RoomJoinsEntityDTO;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.plugin.common.constant.ConstStr;
import com.vhall.component.plugin.common.constant.HttpConstant;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.constant.RoomConstant;
import com.vhall.component.plugin.common.enums.RoomConfigStatusEnum;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.VssToken;
import com.vhall.component.plugin.common.support.VssTokenThreadLocal;
import com.vhall.component.plugin.common.utils.JsonUtil;
import com.vhall.component.plugin.common.utils.RedisLocker;
import com.vhall.component.plugin.core.enums.SendMessageTypeEnum;
import com.vhall.component.plugin.core.service.OssService;
import com.vhall.component.plugin.core.service.PaasService;
import com.vhall.component.service.exam.ExamCacheService;
import com.vhall.component.service.exam.V2ExamService;
import com.vhall.component.service.exam.constant.ExamConst;
import com.vhall.component.service.notice.NoticesService;
import com.vhall.component.service.room.RoomInnerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.stream.RecordId;
import org.springframework.data.redis.connection.stream.StreamRecords;
import org.springframework.data.redis.connection.stream.StringRecord;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * @author song.dong
 * @date 2021-07-16 18:34
 */
@Slf4j
@Service
public class V2ExamServiceImpl implements V2ExamService {

    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private RoomInnerService roomInnerService;

    @Autowired
    private ExamRoomLkMapper examRoomLkMapper;

    @Autowired
    private PaasService paasService;

    @Autowired
    private OssService ossService;

    @Autowired
    private ExamAnswersMapper examAnswersMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private NoticesService noticesService;

    @Value("${vhall.exam.stream-name:exam-stream}")
    public String streamName;

    @Autowired
    private ExamCacheService examCacheService;

    /**
     * 房间试卷详情
     *
     * @param vo 考卷创建参数
     * @return paper info
     */
    @Override
    public ExamPublishInfoRspVo publishInfo(ExamVo vo) {
        ExamPublishInfoRspVo result = new ExamPublishInfoRspVo();
        // 1、查询考试信息。
        ExamEntity exam = getExam(vo.getExamId(), null);
        // 2、查询绑定信息。
        LambdaQueryWrapper<RoomExamLkEntity> query = Wrappers.lambdaQuery();
        query.eq(RoomExamLkEntity::getRoomId, vo.getRoomId());
        query.eq(RoomExamLkEntity::getExamId, vo.getExamId());
        RoomExamLkEntity lk = examRoomLkMapper.selectOne(query);
        if (lk == null) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_PAPER_NOT_EXIST);
        }
        //3、剩余答题时间 = 发布时间 + 考试时长 - 当前时间
        long downTime = 0;
        if (lk.getPublishTime() != null && exam.getLimitTime() != null) {
            Long now = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
            Long sum = Long.valueOf(lk.getPublishTime()) + Long.valueOf(exam.getLimitTime());
            downTime = now < sum ? (now - sum) : 0;
        }

        BeanUtils.copyProperties(exam, result);
        BeanUtils.copyProperties(lk, result);
        result.setDownTime(downTime);
        return result;
    }

    @Override
    public Boolean answer(ExamAnswerReqVo vo) {
        // 1、获取当前用户
        VssToken token = VssTokenThreadLocal.getToken();
        Integer accountId = token.getThirdPartyUserId();
        vo.setAccountId(accountId);
        String key = ExamConst.EXAM_ANSWER + "lock:" + vo.getExamId() + "-" + vo.getRoomId() + "-" + vo.getAccountId();
        boolean lock = RedisLocker.tryLock(key, "1", 90 * 1000L);
        if (!lock) {
            throw new BusinessException(BizErrorCode.BIZ_SUBMIT_REPEAT);
        }
        // 2、获取考试详情
        ExamEntity exam = getExam(vo.getExamId(), String.valueOf(vo.getRoomId()));
        // 3、判断是否超出提交时间
        /*LambdaQueryWrapper<RoomExamLkEntity> query = Wrappers.lambdaQuery();
        query.eq(RoomExamLkEntity::getRoomId, vo.getRoomId());
        query.eq(RoomExamLkEntity::getExamId, vo.getExamId());*/
        RoomExamLkEntity lk = examCacheService.getRoomExamLk(vo.getRoomId(), vo.getExamId());
        if (lk == null) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_NOT_EXIST);
        }
        // 超出提交10秒以上不允许提交，给自动提交预留时间。
        Long now = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
        if (lk.getIsFinish() == 1 && now - lk.getFinishTime() > 10) {
            throw new BusinessException(BizErrorCode.BIZ_SUBMIT_FAILED);
        }
        // 限时试卷判断是否到结束时间，当前时间大于等于结束时间。
        // 结束时间 考试发布时间 + 限时时长
        if (lk.getIsFinish() == 0 && lk.getPublishTime() != null && exam.getLimitTime() != null && !Objects.equals(0, exam.getLimitTime())) {
            long finishTime = (long) lk.getPublishTime() + (long) exam.getLimitTime();
            if (now >= finishTime) {
                // examFinish(String.valueOf(vo.getRoomId()), vo.getExamId());
                ExamVo param = new ExamVo();
                param.setExamId(vo.getExamId());
                param.setRoomId(String.valueOf(vo.getRoomId()));
                examFinish(token.getThirdPartyUserId(), param);
            }
        }
        // 开始结束时间
        if (vo.getStartTime() == null || vo.getStartTime() < lk.getPublishTime()) {
            vo.setStartTime(Long.valueOf(lk.getPublishTime()));
        }
        vo.setEndTime(now);
        // 加入队列用户加入集合
//        String answererSetKey = ExamConst.EXAM_ANSWER_ACCOUNTIDS + vo.getExamId();
        String answererSetKey = RedisKey.EXAM_ANSWER_ACCOUNTS_SET + vo.getExamId();
        redisTemplate.opsForSet().add(answererSetKey, String.valueOf(vo.getAccountId()));
        redisTemplate.expire(answererSetKey, 60L * 30L, TimeUnit.SECONDS);
        // 发送消息
        String msg = JSON.toJSONString(vo);
        try {
            StringRecord rmsg = StreamRecords.string(Collections.singletonMap(HttpConstant.DATA, msg))
                    .withStreamKey(streamName);
            RecordId recordId = redisTemplate.opsForStream().add(rmsg);
            log.info("回答消息发送成功,返回值为：[{}],具体消息为：[{}]", recordId, msg);
        } catch (Exception e) {
            log.error("回答消息发送失败,[" + msg + "]", e);
            return false;
        }
        return true;
    }

    /**
     * 发布试卷
     *
     * @param vo        试卷vo
     * @param accountId 账户id
     */
    @Override
    public Boolean publish(Integer accountId, ExamVo vo) {
        Object inExamId = redisTemplate.opsForHash().get(RedisKey.INTERACT_TOOL + vo.getRoomId(), "in_exam");
        if (Objects.nonNull(inExamId)) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_TAKING);
        }
        ExamEntity exam = getExam(vo.getExamId(), null);
        RoomsEntityDTO room = roomInnerService.getRoomInfo(vo.getRoomId());
        if (room == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        RoomJoinsEntityDTO roomjoin = roomInnerService.getRoomJoinInfo(accountId, vo.getRoomId());
        if (roomjoin == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        if (Integer.valueOf(roomjoin.getRoleName()).equals(2)) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_NO_ACCESS);
        }
        LambdaQueryWrapper<RoomExamLkEntity> query = Wrappers.lambdaQuery();
        query.eq(RoomExamLkEntity::getRoomId, vo.getRoomId());
        query.eq(RoomExamLkEntity::getExamId, vo.getExamId());
        RoomExamLkEntity lk = examRoomLkMapper.selectOne(query);
        if (lk == null) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_PAPER_NOT_EXIST);
        }
        JSONObject jj = paasService.getFormInfo(String.valueOf(exam.getExamId()));
        jj.put("score", exam.getScore());
        jj.put("question_num", exam.getQuestionNum());
        jj.put("limit_time", exam.getLimitTime());
        jj.put("exam_title", exam.getTitle());
        jj.put("publish_time", DateUtil.currentSeconds());
        String fileName = exam.getExamId() + ".json";
        String oosPath = "upload/exam/" + fileName;

        InputStream stream = new ByteArrayInputStream(jj.toJSONString()
                .getBytes(StandardCharsets.UTF_8));
        String jsonpath = ossService.upload(stream, oosPath, "exam");
        // 此处调用无前缀的oss请求，和php保持一致，不然前端无法获取
//        String jsonpath = ossService.uploadByPerfix(stream, oosPath, "exam");

        //修改發佈信息
        lk.setPublish(1);
        lk.setPublishTime(Math.toIntExact(LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"))));
        lk.setAccountId(room.getAccountId());
        examRoomLkMapper.updateById(lk);
        //設置考試狀態
        redisTemplate.opsForHash().put(RedisKey.INTERACT_TOOL_RECORDS + vo.getRoomId(), "has_exam", "1");
        redisTemplate.opsForHash().put(RedisKey.INTERACT_TOOL + vo.getRoomId(), "in_exam", String.valueOf(vo.getExamId()));

        // php是队列实现 java用定时任务去实现
        if (exam.getLimitTime() > 0) {
            sendPush(accountId, vo, exam.getLimitTime());
        }
        HashMap<String, Object> map = Maps.newHashMap();
        map.put("type", SendMessageTypeEnum.EXAM_PUSH.getType());
        map.put("exam_id", vo.getExamId());
        map.put("nick_name", roomjoin.getNickname());
        map.put("room_join_id", roomjoin.getAccountId());
        map.put("room_role", roomjoin.getRoleName());
        map.put("info_url", jsonpath);
        paasService.sendMessage(room.getChannelId(), JsonUtil.toJsonString(map));
//        noticesService.sendNotice(vo.getRoomId(), JsonUtil.toJsonString(vo.getExamId()), roomjoin.getAccountId(), "exam_push");

        //设置考试开关状态
        roomInnerService.updateConfigValueByRoomId(vo.getRoomId(), 1, RoomConfigStatusEnum.EXAM_STATUS.getValue());
        return Boolean.TRUE;
    }

    private void sendPush(Integer accountId, ExamVo vo, Integer limitTime) {
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("hand-in-paper-pool-%d").build();

        //Common Thread Pool
        ScheduledThreadPoolExecutor executor1 = new ScheduledThreadPoolExecutor(1, namedThreadFactory);
        executor1.schedule(() -> {
                    log.info("执行触发器任务开始,{},{}", accountId.toString(), JsonUtil.toJsonString(vo));
                    examFinish(accountId, vo);
                    log.info("执行触发器任务结束");
                },
                limitTime, TimeUnit.SECONDS);
        executor1.shutdown();
    }

    @Override
    public ExamGetNumRspVo getNum(ExamGetNumReqVo vo) {
        ExamGetNumRspVo result = new ExamGetNumRspVo();
        if (StringUtils.isNotBlank(vo.getEndDate())) {
            String endTime = vo.getEndDate();
            if (endTime.contains(ConstStr.TIME_ZERO)) {
                endTime = endTime.replace(ConstStr.TIME_ZERO, ConstStr.TIME_FULL);
            } else {
                endTime = endTime + " " + ConstStr.TIME_FULL;
            }
            vo.setEndDate(endTime);
        }
        LambdaQueryWrapper<RoomExamLkEntity> queryOfLk = Wrappers.lambdaQuery();
        queryOfLk.eq(StringUtils.isNotBlank(vo.getRoomId()), RoomExamLkEntity::getRoomId, vo.getRoomId());
        queryOfLk.eq(StringUtils.isNotBlank(vo.getAccountId()), RoomExamLkEntity::getAccountId, vo.getAccountId());
        queryOfLk.gt(StringUtils.isNotBlank(vo.getBeginDate()), RoomExamLkEntity::getCreatedAt, vo.getBeginDate());
        queryOfLk.lt(StringUtils.isNotBlank(vo.getEndDate()), RoomExamLkEntity::getCreatedAt, vo.getEndDate());
        Integer byRoomNum = examRoomLkMapper.selectCount(queryOfLk);
        result.setByRoomNum(byRoomNum);

        LambdaQueryWrapper<ExamAnswerEntity> queryOfEa = Wrappers.lambdaQuery();
        queryOfEa.eq(StringUtils.isNotBlank(vo.getRoomId()), ExamAnswerEntity::getRoomId, vo.getRoomId());
        queryOfEa.eq(StringUtils.isNotBlank(vo.getAccountId()), ExamAnswerEntity::getAccountId, vo.getAccountId());
        queryOfEa.gt(StringUtils.isNotBlank(vo.getBeginDate()), ExamAnswerEntity::getCreatedAt, vo.getBeginDate());
        queryOfEa.lt(StringUtils.isNotBlank(vo.getEndDate()), ExamAnswerEntity::getCreatedAt, vo.getEndDate());
        Integer byAccountNum = examAnswersMapper.selectCount(queryOfEa);
        result.setByAccountNum(byAccountNum);
        return result;
    }

    @Override
    public Boolean cancelPublish(ExamVo vo) {
        boolean result = true;
        // 0、判断房间是否存在
        RoomsEntityDTO roomsEntityInfo = roomInnerService.getRoomsEntityInfo(vo.getRoomId());
        if (roomsEntityInfo == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        // 1、获取当前用户信息。
        VssToken token = VssTokenThreadLocal.getToken();
        Integer accountId = token.getThirdPartyUserId();
        // 2、查询考试信息。
        ExamEntity exam = getExam(vo.getExamId(), null);

        // 3、查找joinuser。
        RoomJoinsEntityDTO joinUser = roomInnerService.getRoomJoinsByRoomIdAndThirdId(vo.getRoomId(), accountId);
        if (RoomConstant.AUDIENCE.equals(joinUser.getRoleName())) {
            throw new BusinessException(BizErrorCode.BIZ_NO_PERMISSION);
        }
        // 4、查询绑定信息。并修改数据库中的状态。
        LambdaQueryWrapper<RoomExamLkEntity> query = Wrappers.lambdaQuery();
        query.eq(RoomExamLkEntity::getRoomId, vo.getRoomId());
        query.eq(RoomExamLkEntity::getExamId, vo.getExamId());
        RoomExamLkEntity lk = examRoomLkMapper.selectOne(query);
        if (lk != null) {
            LambdaUpdateWrapper<RoomExamLkEntity> update = Wrappers.lambdaUpdate();
            update.set(RoomExamLkEntity::getPublish, 0)
                    .eq(RoomExamLkEntity::getExamId, lk.getExamId());
            int update1 = examRoomLkMapper.update(null, update);
            result = update1 > 0;
        }
        // 5、删除考试中状态。
        delGlobalStatus(vo.getRoomId());
        return result;
    }

    @Override
    public Map<String, Boolean> checkSurvey(Token token, ExamVo vo) {
        RoomJoinsEntityDTO joinUser = roomInnerService.getRoomJoinInfo(token.getAccountId(), vo.getRoomId());
        if (joinUser == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        String roomId = vo.getRoomId();
        Integer examId = vo.getExamId();
        LambdaQueryWrapper<ExamAnswerEntity> answerWrapper = Wrappers.lambdaQuery();
        answerWrapper.eq(ExamAnswerEntity::getExamId, examId).eq(ExamAnswerEntity::getRoomId, roomId)
                .eq(ExamAnswerEntity::getJoinId, joinUser.getJoinId());
        Integer answerCount = examAnswersMapper.selectCount(answerWrapper);

        boolean examFinishStatus = examCacheService.getExamFinishStatus(roomId, examId);
        Map<String, Boolean> result = new HashMap<>(4);
        result.put("is_answer", answerCount > 0);
        result.put("is_finish", examFinishStatus);
        return result;
    }

    private void delGlobalStatus(String roomId) {
        redisTemplate.opsForHash().delete(RedisKey.INTERACT_TOOL + roomId, ExamConst.DURING_THE_EXAMINATION);
    }

    @Override
    public Boolean gradeCheck(ExamVo reqVO, Integer accountId) {
        //1.条件验证
        RoomExamLkEntity examLk = getExamLk(reqVO.getExamId(), reqVO.getRoomId());
        // 1.1操作用户验证
        if (!Objects.equals(examLk.getAccountId(), accountId)) {
            throw new BusinessException(BizErrorCode.BIZ_NO_PERMISSION);
        }
        // 1.2流程验证
        if (!Objects.equals(examLk.getIsFinish(), 1)) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_TAKING);
        }
        if (DateUtil.currentSeconds() - examLk.getFinishTime() < ExamConst.SUBMIT_REMAIN_TIME) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_COLLECTING);
        }
        // 2.判断队列中是否有未处理数据
        String key = RedisKey.EXAM_ANSWER_ACCOUNTS_SET + reqVO.getExamId();
        // 2.1提交数量
        Long submitCount = redisTemplate.opsForSet().size(key);
        // 2.2判断是否有未批阅数据
        Integer answerCount = getAnswerCount(reqVO.getExamId());
        if (answerCount < submitCount) {
            return false;
        }
        return true;
    }

    @Override
    public Boolean gradePush(ExamVo reqVO, Integer accountId) {

        ExamEntity exam = getExam(reqVO.getExamId(), reqVO.getRoomId());
        RoomJoinsEntityDTO roomJoinInfo = roomInnerService.getRoomJoinInfo(accountId, reqVO.getRoomId());
        if (roomJoinInfo == null) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_USER);
        }
        if (Objects.equals(roomJoinInfo.getRoleName(), "2")) {
            throw new BusinessException(BizErrorCode.BIZ_NO_PERMISSION);
        }
        RoomExamLkEntity examLk = getExamLk(reqVO.getExamId(), reqVO.getRoomId());
        if (!Objects.equals(examLk.getPublish(), 1)
                || !Objects.equals(examLk.getIsFinish(), 1)
                || !Objects.equals(examLk.getIsGrade(), 1)) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_NOT_PUBLISH_RESULT);
        }
        examLk.setIsPushGrade(1);
        examRoomLkMapper.updateById(examLk);
        // 构建消息请求体
        JSONObject object = new JSONObject();
        object.put("type",  SendMessageTypeEnum.EXAM_PUSH_GRADE.getType());
        object.put("exam_id", reqVO.getExamId());
        object.put("nick_name", roomJoinInfo.getNickname());
        object.put("room_join_id", roomJoinInfo.getAccountId());
        object.put("room_role", roomJoinInfo.getRoleName());
        String body = JsonUtil.toJsonString(object);
        RoomsEntityDTO room = roomInnerService.getRoomInfo(reqVO.getRoomId());
        paasService.sendMessage(room.getChannelId(), body);
        // 发问卷发送公告信息
//        noticesService.sendNotice(reqVO.getRoomId(), reqVO.getExamId().toString(),
//                examLk.getAccountId(), "exam_push_grade");
        return true;
    }

    @Override
    public Boolean examFinish(Integer accountId, ExamVo vo) {

        String lockKey = RedisKey.EXAM_FINISH_SUBMIT_LOCK + vo.getExamId();

        boolean lock = RedisLocker.tryLock(lockKey, "1", 60000);
        if (!lock) {
            return false;
        }

        getExam(vo.getExamId(), vo.getRoomId());

        // 更新关联状态
        RoomExamLkEntity lk = getExamLk(vo.getExamId(), vo.getRoomId());
        if (lk.getPublish() != 1) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_NOT_PUBLISH);
        }

        lk.setIsFinish(1);
        lk.setFinishTime(DateUtil.currentSeconds());
        examRoomLkMapper.updateById(lk);

        // 删除考试中状态
        delGlobalStatus(vo.getRoomId());


        RoomsEntityDTO room = roomInnerService.getRoomInfo(vo.getRoomId());
        // 发送消息
        Map<String, Object> msg = new HashMap<>(16);
        msg.put("type", SendMessageTypeEnum.EXAM_FINISH.getType());
        msg.put("exam_id", vo.getExamId());
        paasService.sendMessage(room.getChannelId(), JSON.toJSONString(msg));

        // 发送公告
//        noticesService.sendNotice(vo.getRoomId(), vo.getExamId().toString(), lk.getAccountId(), "exam_finish");

        // 大数据上报
        return true;
    }

    @Override
    public Boolean setGrade(VssToken token, ExamVo vo) {

        ExamEntity exam = getExam(vo.getExamId(), vo.getRoomId());

        RoomJoinsEntityDTO joins = roomInnerService.getRoomJoins(token.getThirdPartyUserId(), vo.getRoomId());
        if (joins == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        if (joins.getRoleName().equals(RoomConstant.AUDIENCE)) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_NO_ACCESS);
        }

        RoomExamLkEntity lk = getExamLk(vo.getExamId(), vo.getRoomId());
        if (lk.getIsFinish() != 1 || lk.getPublish() != 1) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_NOT_FINISH);
        }
        if (DateUtil.currentSeconds() - lk.getFinishTime() < ExamConst.SUBMIT_REMAIN_TIME) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_COLLECTING);
        }

        lk.setIsGrade(1);
        lk.setUpdatedAt(LocalDateTime.now());
        examRoomLkMapper.updateById(lk);

        return true;
    }

    @Override
    public PageVO<AnsweredExamResVo> answeredExam(AnsweredExamReqVo vo) {
        Page<AnsweredExamResVo> page = new Page<>(vo.getPage(), vo.getPageSize());
        IPage<AnsweredExamResVo> pages = examAnswersMapper.selectAnsweredExam(page, vo.getRoomId(),
                vo.getAccountId(), vo.getKeyword());

        PageVO<AnsweredExamResVo> result = new PageVO<AnsweredExamResVo>(vo.getPage(), vo.getPageSize(),
                Integer.parseInt(page.getTotal() + ""), pages.getRecords());
        return result;
    }

    /**
     * 根据exam_id和room_id获取房间和试卷的关系
     *
     * @param examId 试卷Id
     * @param roomId 房间Id
     * @return 返回值
     */
    private RoomExamLkEntity getExamLk(Integer examId, String roomId) {
        return examCacheService.getRoomExamLk(roomId, examId);
        /*String key = RedisKey.EXAM_INFO + roomId + "and" + examId;
        RoomExamLkEntity roomExamLkInfo;
        roomExamLkInfo = JSONObject.parseObject(redisTemplate.opsForValue().get(key), RoomExamLkEntity.class);
        if (roomExamLkInfo == null) {
            LambdaQueryWrapper<RoomExamLkEntity> where = Wrappers.lambdaQuery();
            where.eq(RoomExamLkEntity::getExamId, examId)
                    .eq(RoomExamLkEntity::getRoomId, roomId)
                    .last("limit 1");
            roomExamLkInfo = examRoomLkMapper.selectOne(where);
            if (roomExamLkInfo == null) {
                throw new BusinessException(BizErrorCode.COMP_EXAM_PAPER_NOT_EXIST);
            }

        }
        return roomExamLkInfo;*/
    }

    private Integer getAnswerCount(Integer examId) {
        LambdaQueryWrapper<ExamAnswerEntity> where = Wrappers.lambdaQuery();
        where.eq(ExamAnswerEntity::getExamId, examId)
                .eq(ExamAnswerEntity::getIsGraded, 1);
        return examAnswersMapper.selectCount(where);

    }

    /**
     * 根据exam_id和room_id获取试卷及房间详情
     *
     * @param examId 试卷id
     * @param roomId 房间id
     * @return 返回值
     */
    private ExamEntity getExam(Integer examId, String roomId) {
        // ExamEntity exam = examMapper.selectById(examId);
        ExamEntity exam = examCacheService.getExam(examId);
        if (exam == null) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_PAPER_NOT_EXIST);
        }
        if (StringUtils.isNotBlank(roomId)) {
            RoomsEntityDTO room = roomInnerService.getRoomInfo(roomId);
            if (room == null) {
                throw new BusinessException(BizErrorCode.EMPTY_ROOM);
            }
            if (!room.getAccountId().equals(exam.getAccountId())) {
                throw new BusinessException(BizErrorCode.COMP_EXAM_PAPER_NOT_EXIST);
            }
        }
        return exam;
    }

 /*   private void pushToRedis(String key, JSONObject value) {
        redisTemplate.opsForSet().add(RedisKey.QUEUE_NAMES_KEY, key);
        redisTemplate.opsForList().rightPush(key, value.toString());
    }
*/
}
